home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 1 / PC Actual CD 01.iso / trucos / c / c.wri < prev    next >
Encoding:
Text File  |  1995-02-10  |  40.7 KB  |  2,198 lines

  1.  
  2.  
  3.  
  4. LENGUAJE C
  5.  
  6. CONTROL DE DISQUETERAS
  7.  
  8. Para mejorar la presentaci≤n de un programa es importante tener un
  9. control total de todos los errores que se puedan presentar. Una buena
  10. fuente de problemas son los accesos a las disqueteras. Por ejemplo,
  11. un problema muy clßsico es el intento de acceso a una disquetera sin
  12. disco, pues nos encontramos ante el clßsico mensaje de ½Anular,
  13. Repetir, Descartar?╗, algo poco deseable dentro de un programa.
  14. Avisar de todos los problemas que se puedan presentar es una buena
  15. forma de mejorar la calidad de un programa.
  16.  
  17. Mediante la rutina biosdisk podemos saber el estado de la disquetera y
  18. asφ evitar los errores que acabamos de mencionar. Por ejmplo, antes
  19. de abrir un fichero de un disco, podemos ver si realmente estß el
  20. disco en la disquetera, y en caso afirmativo, abrirlo. Para comprobar
  21. el estado podemos utilizar el siguiente c≤digo:
  22.  
  23. #include <bios.h>
  24.  
  25. main() {
  26.  
  27. int r, unidad = 0;
  28.  
  29. char b[512];
  30.  
  31. r=biosdisk(4,unidad,0,0,0,1,b);
  32.  
  33. r=biosdisk(4,unidad,0,0,0,1,b);
  34.  
  35. switch(r) {
  36.  
  37.  case 0x02: printf("Disco no formateado");break;
  38.  
  39.  case 0x08:
  40.  
  41.  case 0x09: printf("Fallo en el DMA");break;
  42.  
  43.  case 0x0C: printf("Tipo de disco no encontrado");break;
  44.  
  45.  case 0x10: printf("Error en el CRC");break;
  46.  
  47.  case 0x20: printf("Fallo en la controladora");break;
  48.  
  49.  case 0x40: printf("Fallo de b·squeda");break;
  50.  
  51.  case 0x80: printf("No hay disco en la disquetera");break;
  52.  
  53.  default : printf("Ok");break;
  54.  
  55.  }
  56.  
  57. }
  58.  
  59.  
  60. La variable unidad vale 0 para A: y 1 para B:. Se llama dos veces
  61. seguidas a la funci≤n biosdisk, ya que la primera vez devuelve un valor
  62. que indica si se ha encontrado un disco, pero sin ver su estado.
  63.  
  64. Ricard Forner Gili
  65.  
  66. Barcelona
  67.  
  68.  
  69. SUPER PIXEL
  70.  
  71. Este programa (realizado en ½Quick C╗ de Microsoft, aunque fßcilmente
  72. implementable en ½Turbo C╗) nos proporciona una nueva rutina para
  73. imprimir un pixel en una VGA 640x480. La nueva rutina estß realizada
  74. en ensamblador y proporciona una mayor velocidad que la instrucci≤n
  75. ½_setpixel╗. En este programa podemos comparar las dos instrucciones
  76. para ver la diferencia de velocidad de una a otra.
  77.  
  78. #include <graph.h>
  79.  
  80. void DP(int pagina,int i,int p,int color);
  81.  
  82. main()
  83.  
  84. {
  85.  int x,y;char ca;
  86.  
  87.  _setvideomode(_VRES16COLOR);
  88.  
  89.  _clearscreen(_GCLEARSCREEN);
  90.  
  91.  printf("1.- Impresi≤n en 'C' (setpixel).\n");
  92.  
  93.  printf("2.- Impresi≤n 'ASSEMBLY' (dp).\n");
  94.  
  95.  while (ca!='1' && ca!='2') ca=getch();
  96.  
  97.  for (y=0;y<480;y=y+10)
  98.  
  99.  for (x=0;x<640;x=x+1)
  100.  
  101.  if (ca=='1') {_setcolor(1);_setpixel(x,y);}
  102.  
  103.  else DP(0,x,y,1);
  104.  
  105.  _setvideomode(_DEFAULTMODE);
  106.  
  107. }
  108.  
  109. void DP(int pagina,int t,int p,int color)
  110.  
  111. {
  112.  
  113.  _asm{
  114.  
  115.  mov bh,[bp+6];
  116.  
  117.  mov cx,[bp+8];
  118.  
  119.  mov dx,[bp+10];
  120.  
  121.  mov al,[bp+12];
  122.  
  123.  mov ah,0Ch;
  124.  
  125.  int 10h;
  126.  
  127.  }
  128.  
  129. }
  130.  
  131. Juan Vercher Martφnez
  132.  
  133. Gandφa (Valencia)
  134.  
  135.  
  136.  
  137. INCLUYA 16 COLORES EN EL FONDO
  138.  
  139. Este programa es un ejempo de c≤mo utilizar los colores comprendidos
  140. entre el 8 y el 15 como color de fondo. Hemos de recordar que para el
  141. color de fondo s≤lo podemos utilizar los colores del 0 al 7, de ahφ la
  142. motivaci≤n de este truco.
  143.  
  144. La rutina ½parpadeo()╗ funciona por medio de la interrupci≤n 10h
  145. subservicio 03h, que permite activar o desactivar el atributo de
  146. parpadeo. La ROM BIOS utiliza el parpadeo por defecto, pero cambiando
  147. el valor del atributo se pueden utilizar los 16 colores para el fondo.
  148. El valor que se pasa en BL determina si el valor estß activado (01h) o
  149. desactivado (00h).
  150.  
  151. Es necesario utilizar la funci≤n ½textattr()╗ (para definir los dos
  152. colores se puede emplear la f≤rmula ColorTexto+ColorFondo*16) para
  153. cambiar el color, ya que con las funciones ½textcolor()╗ y
  154. ½textbackground()╗ no es posible, puesto que reestablecen el atributo
  155. para parpadeo.
  156.  
  157. #include <stdio.h>
  158.  
  159. #include <dos.h>
  160.  
  161. #include <conio.h>
  162.  
  163. enum BOOLEAN {OFF, ON};
  164.  
  165. void parpadeo (enum BOOLEAN activar);
  166.  
  167. void parpadeo (enum BOOLEAN activar)
  168.  
  169. {
  170.  
  171.  union REGS regs;
  172.  
  173.  regs.h.bl=activar ? 0x01 : 0x00;
  174.  
  175.  regs.h.ah=0x10;
  176.  
  177.  regs.h.al=0x03;
  178.  
  179.  int86(0x10,®s,®s);
  180.  
  181. }
  182.  
  183. void main()
  184.  
  185. {
  186.  
  187.  int i,j;
  188.  
  189.  enum BOOLEAN parpadear;
  190.  
  191.  textattr( 0 + 15 * 16);
  192.  
  193.  cprintf("\n\rFONDO");
  194.  
  195.  for(i=1;i<16;i++) cprintf(" %2d ",i);
  196.  
  197.  for(i=0;i<16;i++)
  198.  
  199.  for (j=0;j<16;j++)
  200.  
  201.  {
  202.  
  203.  textattr(i+j*16);
  204.  
  205.  cprintf("Texto");
  206.  
  207.  }
  208.  
  209.  textattr(0+15*16);
  210.  
  211.  cprintf("Pulsa Esc para finalizar, otra tecla "
  212.  
  213.  "para cambiar el atributo de parpadeo...");
  214.  
  215.  parpadear = ON;
  216.  
  217.  while(i!=27)
  218.  
  219.  {
  220.  
  221.  parpadear=!parpadear;
  222.  
  223.  parpadeo(parpadear);
  224.  
  225.  i=getch();
  226.  
  227.  }
  228.  
  229.  parpadeo(ON);
  230.  
  231. }
  232.  
  233.  
  234. Antonio Jes·s Ollero Sanguino
  235.  
  236. Casar de Cßceres (Cßceres)
  237.  
  238.  
  239.  
  240. TECLADOS VELOCES
  241.  
  242. La ROM-BIOS permite obtener las teclas pulsadas a una velocidad mßxima
  243. de 30 caracteres por segundo y con un retardo de autorrepetici≤n de
  244. 0,25 segundos. Algunas veces interesa que el retardo de
  245. autorrepetici≤n sea menor y leer a mßs velocidad. Esta rutina
  246. soluciona este problema.
  247.  
  248. #include <Dos.h>
  249.  
  250. usigned char obt_tecla (void);
  251.  
  252. {
  253.  
  254.  unsigned int *cabeza=(unsigned int *) (0x0000041a);
  255.  
  256.  unsigned int *cola=(unsigned int *) (0x0000041c);
  257.  
  258.  *cabeza=*cola
  259.  
  260.  return portb(0x60);
  261.  
  262. }
  263.  
  264. El funcionamiento de la rutina estß basado en la lectura del c≤digo de
  265. letra pulsada directamente del puerto, y ademßs se vacφa el buffer del
  266. teclado para que no se llene, ya que no se saca la tecla mediante
  267. ninguna llamada a la ROM-BIOS.
  268.  
  269. Utilidad: Esta funci≤n puede ser de gran utilidad para juegos, en los
  270. cuales se requiere mover un grßfico o ejecutar una acci≤n seg·n la
  271. tecla pulsada. En estos casos suele resultar bastante lento tener que
  272. esperar los 0,25 segundos para que el ordenador detecte que se
  273. mantiene pulsada la misma tecla.
  274.  
  275. Jorge Pastor Mondejar
  276.  
  277. Molina de Segura (Murcia)
  278.  
  279.  
  280. SCROLL DE TEXTO
  281.  
  282. Esta rutina realiza un scroll en pantalla mediante el uso de las
  283. interrupciones de la BIOS. La ventaja de esta tΘcnica radica en que
  284. permite la realizaci≤n un scroll en una ventana.
  285.  
  286. Los parßmetros que se le pasan a la rutina son los siguientes:
  287.  
  288. Fijo: atributo; este parßmetro representa el color.
  289.  
  290. Fil: fila superior de la ventana donde se realiza el
  291. scroll.
  292.  
  293. Col: columna mßs a la izquierda de la ventana donde se hace el
  294. scroll.
  295.  
  296. Fils: fila inferior de la ventana donde se realiza el
  297. scroll.
  298.  
  299. Col: columna mßs a la derecha de la ventana donde se hace el
  300. scroll.
  301.  
  302. Atr: Funci≤n a realizar. Dependiendo de los parßmetros que le
  303. pasemos aquφ podrß realizar ½scroles╗ hacia arriba, abajo, etc, (es
  304. conveniente investigar).
  305.  
  306. Numfils: n·mero de lφneas a mover.
  307.  
  308. #include <bios.h>
  309.  
  310. #include <stdio.h>
  311.  
  312. #include <conio.h>
  313.  
  314. union REGS inregs, outregs;
  315.  
  316. void scroll (int fijo, int fil, int col, int fils, int cols, int atr,
  317. int numfils)
  318.  
  319. {
  320.  
  321. inregs.h.ah = atr;
  322.  
  323. inregs.h.al = numfils;
  324.  
  325. inregs.h.bh = fijo;
  326.  
  327. inregs.h.ch = fil;
  328.  
  329. inregs.h.cl = col;
  330.  
  331. inregs.h.dh = fils;
  332.  
  333. inregs.h.dl = cols;
  334.  
  335. int86(0x10, &inregs, &outregs);
  336.  
  337. }
  338.  
  339. /* Programa de ejemplo */
  340.  
  341. main()
  342.  
  343. {
  344.  
  345. int i,u;
  346.  
  347. clrscr();
  348.  
  349. for (i=0; i<30; i++)
  350.  
  351. {
  352.  
  353. gotoxy(50,3);
  354.  
  355. printf("%d",i);
  356.  
  357. scroll(7,2,49,19,60,7,1);
  358.  
  359. getch();
  360.  
  361. }
  362.  
  363. }
  364.  
  365. David G. Peris
  366.  
  367. Barcelona
  368.  
  369.  
  370. SALIR AL DOS
  371.  
  372. El objetivo de esta rutina es el de poder implementar un shell al DOS
  373. en los men·s de nuestros propios programas.
  374.  
  375. Para realizar este cometido invocaremos una llamada al ½command.com╗
  376. mediante la orden ½SYSTEM╗, una vez que sepamos que el interprete de
  377. comandos estß en nuestro path activo. Si el ½command.com╗ no se
  378. encuentra en el path activo, sale de la funci≤n devolviendo 0, si no
  379. lo ejecuta y cuando se teclea ½EXIT╗ devuelve 1.
  380.  
  381. Para saber si el ½command.com╗ estß a nuestra disposici≤n, utilizamos
  382. la sentencia ½SEARCHPATH╗ de la lφbreria <dir.h>. Si el ½command.com╗
  383. estß disponible devuelve la ruta completa de acceso a Θl; en caso
  384. contrario devuelve ½NULL╗.
  385.  
  386. El programa ha sido compilado mediante ½Turbo C/C++ 1.0╗.
  387.  
  388. #include <dir.h>
  389.  
  390. #include <stdlib.h>
  391.  
  392. #include <conio.h>
  393.  
  394. int dos_shell();
  395.  
  396. /* main de ejemplo */
  397.  
  398. main ()
  399.  
  400. {
  401.  
  402.  if dos_shell()==0)
  403.  
  404.  cprintf("\nNo se encontr≤ COMMAND COM en el path activo\n");
  405.  
  406.  return 0;
  407.  
  408. }
  409.  
  410. int dos_shell()
  411.  
  412. {
  413.  
  414. char *camino=NULL;
  415.  
  416. camino =searchpath("COMMAND.COM");
  417.  
  418. if (camino==NULL) return 0;
  419.  
  420. clrscr();
  421.  
  422. cprintf ("Teclea Exit para volver al programa. \n");
  423.  
  424. system (camino);
  425.  
  426. clrscr();
  427.  
  428. return 1;
  429.  
  430. }
  431.  
  432. JosΘ Luis Moncada Collado
  433.  
  434. Sant Adriß de Bes≤s (Barcelona)
  435.  
  436.  
  437.  
  438. EFECTO OPTICO
  439.  
  440. Este es un peque±o truco para lograr esos efectos ½visuales╗ que tanto
  441. suelen gustar a la gente. Consiste en un CLS muy llamativo, ya que
  442. todo lo que hay en la pantalla de texto desaparecerß como si de niebla
  443. o humo se tratase. Es ideal para programas en modo texto que no
  444. pueden acceder a los trucos que permite el modo grßfico.
  445.  
  446. El programa accede directamente al buffer de vφdeo y ahφ va
  447. incrementando en uno todos los caracteres distintos de 0 (para evitar
  448. un bucle infinito) y todos los distintos de ½ ╗ (para no tocar el
  449. fondo, s≤lo el texto), asφ hasta que no quedan mßs que ceros o ½ ╗
  450. (espacio en blanco) entonces ya se habrß borrado la pantalla.
  451. Funciona tanto en color como en monocromo, y estß realizado con el
  452. Borland C++ 3.1 en ANSI C. Por lo que deberφa funcionar sin problemas
  453. en cualquier compilador de C que cumpla la norma ANSI.
  454.  
  455.  #include <stdio.h>;
  456.  
  457.  #include <dos.h>;
  458.  
  459.  #include <stdlib.h>;
  460.  
  461.  int modo_video(void),modov,humo(void);
  462.  
  463.  char far *mem_video;
  464.  
  465.  main()
  466.  
  467.  {
  468.  
  469.  modov=modo_video();
  470.  
  471.  if ((modov!=2) && (modov!=3) && (modov!=7)) {
  472.  
  473.  printf("\nEl modo de video debe estar en 80 columnas.");
  474.  
  475.  exit(1);
  476.  
  477.  }
  478.  
  479.  if (modov==7)
  480.  
  481.  mem_video = (char far *) 0xb0000000; /*Monocromo*/
  482.  
  483.  else
  484.  
  485.  mem_video = (char far *) 0xb8000000; /*Color */
  486.  
  487.  do{
  488.  
  489.  }while (humo()); /*Mientras humo devuelva un 1 es que hay caracteres*/
  490.  
  491.  printf("Prueba de desaparicion de caracteres realizada");
  492.  
  493.  return(0);
  494.  
  495.  }
  496.  
  497. int modo_video(void)
  498.  
  499.  {
  500.  
  501.  union REGS r;
  502.  
  503.  r.h.ah=15; /*obtiene el modo de video */
  504.  
  505.  return int86(0x10,&r,&r) & 255;
  506.  
  507.  }
  508.  
  509. int humo(void)
  510.  
  511.  {
  512.  
  513.  register char far *p;
  514.  
  515.  int bandera=0;
  516.  
  517.  for (p=mem_video;p<mem_video+80*25*2;p++,p++)
  518.  
  519.  if ((*p!=0) && (*p!=32)){
  520.  
  521.  (*p)++;
  522.  
  523.  bandera=1;
  524.  
  525.  }
  526.  
  527.  return(bandera);
  528.  
  529.  }
  530.  
  531. Antonio Javier Garcφa Martφnez
  532.  
  533. Granada
  534.  
  535.  
  536. GUARDAR Y RESTAURAR PANTALLAS
  537.  
  538. Las siguientes rutinas realizadas en C++ son una mejora de las rutinas
  539. publicadas en el n·mero de febrero para guardar y restaurar pantallas
  540. de texto. Estos procedimientos muestran su utilidad cuando abrimos un
  541. men·, cuadro de dißlogo o ventana y al cerrarlo deseamos que
  542. reaparezca el contenido de la pantalla tal y como estaba
  543. anteriormente.
  544.  
  545. La ventajas que ofrecen las nuevas rutinas es que trabajan
  546. directamente con la memoria de vφdeo. Para ello se basan en el
  547. principio de que los modos de texto de 80x25 disponen de cuatro
  548. pßginas de vφdeo que normalmente no se utilizan. Estos nuevos
  549. procedimientos -½SaveScreen (...)╗ y ½RestScreen(...)╗- copian las
  550. pantallas a otra pßgina, lo que permite que el acceso sea mßs rßpido.
  551.  
  552. Tan s≤lo presentan una desventaja producida por la limitaci≤n de
  553. pßginas de vφdeo disponibles, pues en el modo 80x25 s≤lo disponemos de
  554. tres pßginas libres y en el modo 40x25 de siete pßginas. En cada
  555. pßgina libre podremos guardar una pantalla.
  556.  
  557. El siguiente programa de ejemplo captura la pantalla de texto, despues
  558. espera a que se pulse una tecla, borra la pantalla y espera de nuevo
  559. otra pulsaci≤n de tecla, tras la cual restaura el contenido original
  560. de la pantalla.
  561.  
  562. #include <stdio.h>
  563.  
  564. #include <mem.h>
  565.  
  566. void SaveScreen (unsigned short Pagina);
  567.  
  568. void RestScreen (unsigned short Pagina);
  569.  
  570. void main(void);
  571.  
  572. {
  573.  
  574.  printf ("PC Actual");
  575.  
  576.  int c;
  577.  
  578.  SaveScreen (1);
  579.  
  580.  c=getchar();
  581.  
  582.  clrscr();
  583.  
  584.  c=getchar;
  585.  
  586.  RestScreen(1);
  587.  
  588. }
  589.  
  590.  
  591. // Funciones Principales //
  592.  
  593. void SaveScreen (unsigned short Pagina);
  594.  
  595. {
  596.  unsigned int Pos=Pagina*0x1000;
  597.  
  598.  movedata (0xB800, 0x0000, 0xB800, Pos, 4000);
  599.  
  600. }
  601.  
  602. void RestScreen (unsigned short Pagina);
  603.  
  604. {
  605.  
  606.  unsigned int Pos=Pagina*0x1000;
  607.  
  608.  movedata (0xB800, Pos, 0xB800, 0x0000, 4000);
  609.  
  610. }
  611.  
  612.  
  613. Daniel Sßnchez Teodoro
  614.  
  615. Granada
  616.  
  617.  
  618. ESCALA DE GRISES
  619.  
  620. Esta rutina realizada en Turbo C, aunque fßcilmente adaptable a Pascal
  621. o ensamblador, transforma la paleta de la pantalla MCGA o VGA 256
  622. colores (320 x 200 con 256 colores) a sus correspondientes valores de
  623. la escala de grises. En definitiva, cuando llamamos a esta funci≤n el
  624. grßfico de la pantalla se pone en blanco y negro, tal y como vemos en
  625. muchas mßquinas recreativas.
  626.  
  627. Para transformar la paleta de la pantalla a grises ejecutaremos
  628. gris(0), mientras que para devolver a su estado original una paleta
  629. convertida a escala de grises escribiremos gris(1).
  630.  
  631. Las dos rutinas para gris se pueden incluir en el m≤dulo principal del
  632. programa en C, pero en caso de que deseemos linkar esta funci≤n como
  633. un m≤dulo separado no hay que olvidar incluir el fichero ½.h╗ para
  634. acceder a ella.
  635.  
  636. /* Funci≤n de transformaci≤n de grises
  637.  
  638. #include <dos.h>
  639.  
  640. #define GRIS 0
  641.  
  642. #define COLOR 1
  643.  
  644. void gris(void);
  645.  
  646. static unsigned char paleta_antigua[256][3];
  647.  
  648. static unsigned char activado;
  649.  
  650. void gris (char modo)
  651.  
  652. {
  653.  
  654. switch(modo){
  655.  
  656. case COLOR;
  657.  
  658.  if (!activado) break; /*sale si no hay grises */
  659.  
  660.  _ES = FP_SEG(paleta_antigua); /*Estas dos siempre primero */
  661.  
  662.  _DX = FP_OFF(paleta_antigua);
  663.  
  664.  _AX = 0x1012; /* Funci≤n BIOS para definir PALETA */
  665.  
  666.  _BX = 0;
  667.  
  668.  _CX = 256;
  669.  
  670.  geninterrupt (0x10); /* Llama a la BIOS */
  671.  
  672.  activado=~activado; /* Muta el indicador */
  673.  
  674.  break;
  675.  
  676. case GRIS;
  677.  
  678.  if (activado) break; /*sale si ya hay grises */
  679.  
  680.  _ES = FP_SEG(paleta_antigua); /*Estas dos siempre primero */
  681.  
  682.  _DX = FP_OFF(paleta_antigua);
  683.  
  684.  _AX = 0x1017; /* Salva la paleta de color antigua */
  685.  
  686.  _BX = 0;
  687.  
  688.  _CX = 256;
  689.  
  690.  geninterrupt (0x10); /* Llama a la BIOS */
  691.  
  692.  _AX = 0x101B; /* Pasa a grises */
  693.  
  694.  _BX = 0;
  695.  
  696.  _CX = 256;
  697.  
  698.  geninterrupt (0x10); /* Llama a la BIOS */
  699.  
  700.  activado=~activado; /* Muta el indicador */
  701.  
  702.  break;
  703.  
  704. }
  705.  
  706. }
  707.  
  708. Fichero ½gris.h╗:
  709.  
  710. /* Cabecera del m≤dulo transformador de grises vφa BIOS (MCGA-VGA) */
  711.  
  712. extern void gris(void);
  713.  
  714. #define GRIS 0
  715.  
  716. #define COLOR 1
  717.  
  718. Luis Dφaz Villanueva
  719.  
  720. Madrid
  721.  
  722. Comentario del Laboratorio: La rutina se basa en la utilizaci≤n de la
  723. interrupci≤n 10 de la BIOS (encargada de los servicios de vφdeo),
  724. aunque mßs en concreto en la funci≤n 10, cuya misi≤n es la gesti≤n de
  725. los registros de la paleta de colores. La paleta de colores en el
  726. modo VGA 256 estß formada por 256 registros (uno por color) con tres
  727. valores cada uno (para la cantidad de rojo, verde y azul de cada
  728. color)
  729.  
  730. Para llevar a cabo el truco se hace uso de la subfunci≤n 12, cuya
  731. misi≤n es la asignaci≤n de un bloque de registros de color; la
  732. subfunci≤n 17, que lee un bloque de registros de color, y, por ·ltimo,
  733. de la subfunci≤n 1B, que suma los valores de color para pasar a tonos
  734. de grises. Estas funciones necesitan tener cargado en ES la direcci≤n
  735. del segmento donde se encuentra la tabla donde leeremos o grabaremos
  736. los registros de color de la paleta. Ademßs, en DX debe cargarse el
  737. desplazamiento (offset) de dicha tabla.
  738.  
  739. Para efectuar la llamada a la funci≤n cargamos el 10 (del n·mero de
  740. funci≤n) en el registro AH y el n·mero de subfunci≤n en el registro
  741. AL. Por ejemplo, cuando ejecutamos ½gris(0)╗ en el truco llamamos a
  742. la subfunci≤n 12, por eso en este caso cargamos en AH el 10 y en AL el
  743. 12, lo que es equivalente a cargar 1012 en AX. Una vez que hemos
  744. cargado el valor de la funci≤n a emplear debemos pasar en BX el n·mero
  745. de color desde el que queremos empezar a trabajar; en este caso nos
  746. interesa el primer color (el 0) para convertir toda la paleta.
  747. Ademßs, en CX cargaremos el n·mero de colores que queremos convertir.
  748. Por ·ltimo, modificando los valores de BX y CX conseguiremos tratar
  749. s≤lo un determinado rango de colores. Tras haber cargado todos los
  750. valores en cada uno de los registros se efect·a la llamada a la
  751. interrupci≤n 10.
  752.  
  753.  
  754. RUTINAS PARA LA PALETA
  755.  
  756. Esta librerφa para C puede ser de gran utilidad para todos los
  757. programadores que utilicen cualquier modo grßfico y deseen ½jugar╗ con
  758. la paleta de colores.
  759.  
  760. La funci≤n ½set_rgb╗ sirve para establecer los valores RGB, es decir,
  761. las cantidades de rojo, verde y azul (en este orden) que forman el
  762. color (½col╗). La funci≤n ½get_rgb╗ efect·a el proceso contrario, es
  763. decir, dado el color ½col╗ nos devuelve la cantidad de rojo, verde y
  764. azul que componen dicho color.
  765.  
  766. TambiΘn podremos utilizar ½Make_gradiente╗ para crear una escala de
  767. gradientes. Como argumentos se le pasan los valores RGB (rojo, verde
  768. y azul) del color inicial y del color final, asφ como el color en que
  769. comienza la escala y el n·mero de colores que la compondrßn (si este
  770. ·ltimo argumento es negativo se pueden obtener escalas hacia atras).
  771.  
  772. Por ·ltimo, la funci≤n ½ciclo╗ se utiliza para conseguir que una
  773. secci≤n de la paleta gire o rote sus colores. Se le pasan como
  774. argumentos el color inicial y final del segmento de paleta deseado.
  775. Con este efecto se consigue un resultado especialmente vistoso
  776. utilizßndolo en un bucle, logrando un efecto semejante al utilizado en
  777. algunos programas de fractales (como el Fractint).
  778.  
  779. Un ejemplo de esto ·ltimo es:
  780.  
  781. while (!kbhit())
  782.  
  783. {
  784.  
  785.  ciclo(0,255);
  786.  
  787. }
  788.  
  789.  
  790. La librerφa es la siguiente:
  791.  
  792. #include <dos.h>
  793.  
  794. typedef unsigned char byte;
  795.  
  796. typedef struct
  797.  
  798. {
  799.  
  800.  byte r;
  801.  
  802.  byte g;
  803.  
  804.  byte b;
  805.  
  806. }rgb;
  807.  
  808. void set_rgb (byte r, byte g, byte b, byte col);
  809.  
  810. rgb get_rgb (byte col);
  811.  
  812. void ciclo (byte inicio, byte fin);
  813.  
  814. void make_gradiente (byte, byte, byte, byte, byte, byte, byte, int );
  815.  
  816. void set_rgb (byte r, byte g, byte b, byte col)
  817.  
  818. {
  819.  
  820.  outportb(0x3c8, col);
  821.  
  822.  outportb(0x3c9, r);
  823.  
  824.  outportb(0x3c9, g);
  825.  
  826.  outportb(0x3c9, b);
  827.  
  828. }
  829.  
  830. rgb get_rgb (byte col)
  831.  
  832. {
  833.  
  834.  rgb result;
  835.  
  836.  outportb(0x3c7, col);
  837.  
  838.  result.r=inport(0x3c9);
  839.  
  840.  result.g=inport(0x3c9);
  841.  
  842.  result.b=inport(0x3c9);
  843.  
  844.  return (result);
  845.  
  846. }
  847.  
  848. void ciclo (byte inicio, byte fi)
  849.  
  850. {
  851.  
  852.  int cont=0;
  853.  
  854.  rgb ci=get_rgb(inicio);
  855.  
  856.  rgb c;
  857.  
  858.  for (cont=inicio; cont <final; cont++)
  859.  
  860.  {
  861.  
  862.  c=get_rgb(cont+1);
  863.  
  864.  set_rgb(c.r, c.g, c.b, cont);
  865.  
  866.  }
  867.  
  868.  set_rgb(ci.r, ci.g, ci.b, final);
  869.  
  870. }
  871.  
  872. void make_gradiente (byte R1, byte G1, byte B1, byte R2,
  873.  
  874.  byte G2, byte B2, byte inicio, int numtonos)
  875.  
  876. {
  877.  
  878.  int deltaR, deltaG, deltaB;
  879.  
  880.  int cont, sent = 1;
  881.  
  882.  int n=abs(numtonos);
  883.  
  884.  byte col=0;
  885.  
  886.  rgb c;
  887.  
  888.  if (n==0) return;
  889.  
  890.  deltaR=R2-R1;
  891.  
  892.  deltaG=G2-G1;
  893.  
  894.  deltaB=B2-B1;
  895.  
  896.  if (numtonos<0) sent=-1;
  897.  
  898.  for (col=ini, cont=0, cont<=n; cont++, col+=sent)
  899.  
  900.  {
  901.  
  902.  c.r =R1+(deltaR*cont/n);
  903.  
  904.  c.g =G1+(deltaR*cont/n);
  905.  
  906.  c.b =B1+(deltaR*cont/n);
  907.  
  908.  set_rgb(c.r, c.g, c.b, col);
  909.  
  910.  }
  911.  
  912. }
  913.  
  914. Fernando Moyano
  915.  
  916. Pamplona
  917.  
  918.  
  919. CAMBIO DE LETRAS
  920.  
  921. Las siguientes rutinas han de ser llamadas desde otra funci≤n, y
  922. permiten convertir los caracteres normales en cursivas, negritas y
  923. subrayadas. Es tarea fßcil partir de estas rutinas para crear otras
  924. que hagan cualquier otra cosa, y es algo que puede ser ·til para
  925. usarlo en alg·n programa, dßndole un toque de distici≤n.
  926.  
  927. #include <dos.h>
  928.  
  929. #include <conio.h>
  930.  
  931. #include <stdio.h>
  932.  
  933. typedef unsigned int word;
  934.  
  935. typedef unsigned char byte;
  936.  
  937. byte far* LoadFont()
  938.  
  939. /*Esta rutina usa las fuentes de 16 bytes*/
  940.  
  941. {
  942.  
  943.  word wSegment,wOffset;
  944.  
  945.  asm{
  946.  
  947.  mov di,bp
  948.  
  949.  mov ah,0x11
  950.  
  951.  mov al,0x30
  952.  
  953.  mov bh,6
  954.  
  955.  int 0x10
  956.  
  957.  push es
  958.  
  959.  push bp
  960.  
  961.  mov bp,di
  962.  
  963.  pop ax
  964.  
  965.  mov wOffset,ax
  966.  
  967.  pop ax
  968.  
  969.  mov wSegment,ax
  970.  
  971.  }
  972.  
  973.  return (byte far*)MK_FP(wSegment,wOffset);
  974.  
  975. }
  976.  
  977. void SetFont(byte far *pby)
  978.  
  979. /*Esta rutina usa las fuentes de 16 bytes*/
  980.  
  981. {
  982.  
  983.  asm{
  984.  
  985.  push bp
  986.  
  987.  mov ah,0x11
  988.  
  989.  mov al,0
  990.  
  991.  mov bh,16 /*16bytes por carßcter*/
  992.  
  993.  mov bl,0
  994.  
  995.  mov cx,97 /*97 caracteres*/
  996.  
  997.  mov dl,'!' /*carßcter a partir del cual comienzo*/
  998.  
  999.  mov dh,0
  1000.  
  1001.  les bp,pby
  1002.  
  1003.  int 0x10
  1004.  
  1005.  pop bp
  1006.  
  1007.  }
  1008.  
  1009. }
  1010.  
  1011. void Bold()
  1012.  
  1013. /*Esta rutina usa las fuentes de 16 bytes*/
  1014.  
  1015. {
  1016.  
  1017.  byte far *pbyOld,pbyNew[16*97];
  1018.  
  1019.  int i;
  1020.  
  1021.  pbyOld=LoadFont();
  1022.  
  1023.  for(i=0;i<16*97;i++)
  1024.  
  1025.  pbyNew[i]=(pbyOld[i+16*33]>>1)|pbyOld[i+16*33];
  1026.  
  1027.  SetFont(pbyNew);
  1028.  
  1029. }
  1030.  
  1031. void Underlined()
  1032.  
  1033. /*Esta rutina usa las fuentes de 16 bytes*/
  1034.  
  1035. {
  1036.  
  1037.  byte far *pbyOld,pbyNew[16*97];
  1038.  
  1039.  int i;
  1040.  
  1041.  pbyOld=LoadFont();
  1042.  
  1043.  for(i=0;i<16*97;i++)
  1044.  
  1045.  if(i%16==15)
  1046.  
  1047.  pbyNew[i]=0xFF;
  1048.  
  1049.  else
  1050.  
  1051.  pbyNew[i]=pbyOld[i+16*33];
  1052.  
  1053.  
  1054.  SetFont(pbyNew);
  1055.  
  1056. }
  1057.  
  1058. void Cursive()
  1059.  
  1060. /*Esta rutina usa las fuentes de 16 bytes*/
  1061.  
  1062. {
  1063.  
  1064.  byte far *pbyOld,pbyNew[16*97];
  1065.  
  1066.  int i;
  1067.  
  1068.  pbyOld=LoadFont();
  1069.  
  1070.  for(i=0;i<16*97;i++)
  1071.  
  1072.  switch(i%16)
  1073.  
  1074.  {
  1075.  
  1076.  case 2:
  1077.  
  1078.  case 3:
  1079.  
  1080.  pbyNew[i]=pbyOld[i+16*33]>>2;
  1081.  
  1082.  break;
  1083.  
  1084.  case 4:
  1085.  
  1086.  case 5:
  1087.  
  1088.  pbyNew[i]=pbyOld[i+16*33]>>1;
  1089.  
  1090.  break;
  1091.  
  1092.  case 10:
  1093.  
  1094.  case 11:
  1095.  
  1096.  pbyNew[i]=pbyOld[i+16*33]<<1;
  1097.  
  1098.  break;
  1099.  
  1100.  case 12:
  1101.  
  1102.  case 13:
  1103.  
  1104.  pbyNew[i]=pbyOld[i+16*33]<<2;
  1105.  
  1106.  break;
  1107.  
  1108.  default:
  1109.  
  1110.  pbyNew[i]=pbyOld[i+16*33];
  1111.  
  1112.  }
  1113.  
  1114.  SetFont(pbyNew);
  1115.  
  1116. }
  1117.  
  1118. Daniel PΘrez Palomar
  1119.  
  1120. Barcelona
  1121.  
  1122.  
  1123.  
  1124. CONTROL DE LA IMPRESORA
  1125.  
  1126. Esta rutina sirve para programas que deseen conocer el estado de la
  1127. impresora antes de mandar algo a imprimir, y en el caso de que no estΘ
  1128. correctamente conectada puedan mandar el c≤digo de error
  1129. correspondiente.
  1130.  
  1131. El programa estß realizado en Borland C++ 2.0, y hace uso de la
  1132. funci≤n ½biosprint╗ de la librerφa ½bios.h╗.
  1133.  
  1134. Estß funci≤n act·a bajo los registros de la BIOS y nos permitirß saber
  1135. si nuestra impresora estß ocupada, tiene alg·n error en el dispositivo
  1136. de entrada/salida, si tiene papel, etc.
  1137.  
  1138. La funci≤n ½biosprint╗ trabaja devolviendo un valor que se guardarß en
  1139. este caso en la variable ½printer╗. Seg·n el valor que reciba
  1140. sabremos su estado. Otra utilidad de esta funci≤n es la de
  1141. reinicializar la impresora una vez ya conectada. Esto puede resultar
  1142. de gran utilidad, si se desean eliminar los datos del buffer de la
  1143. impresora cuando se estß realizando un programa. Se hace cambiando el
  1144. valor ½estado╗ por 1, de tal modo que la impresora se reiniciarß.
  1145.  
  1146. #include <conio.h>
  1147.  
  1148. #include <bios.h>
  1149.  
  1150. #include <stdio.h>
  1151.  
  1152. #define ESTADO 2
  1153.  
  1154. #define PUERTO 0
  1155.  
  1156. int printer;
  1157.  
  1158. main ()
  1159.  
  1160. {
  1161.  
  1162.  clrscr ();
  1163.  
  1164.  textcolor(cyan + blynk);
  1165.  
  1166.  cprintf ("\n ......... ESTADO DE LA IMPRESORA ..........");
  1167.  
  1168.  printer = biosprint (ESTADO, 0, PUERTO);
  1169.  
  1170.  /* La variable printer almacena el estado de la impresora */
  1171.  
  1172.  if (printer & 0x10) printf ("\n\nImpresora conectada...");
  1173.  
  1174.  
  1175.  else
  1176.  
  1177.  printf("\n\nLa impresora no estß conectada...");
  1178.  
  1179.  if (printer & 0x08) printf("\nError en el dispositivo I/O...");
  1180.  
  1181.  else
  1182.  
  1183.  printf("\nNo hay error en el dispositivo I/O...");
  1184.  
  1185.  if (printer & 0x01) printf (\nPaso del tiempo adjudicado...");
  1186.  
  1187.  else
  1188.  
  1189.  printf("\nNO - paso del tiempo adjudicado...");
  1190.  
  1191.  if (printer & 0x20) printf ("\nLa impresora no encuentra el papel...");
  1192.  
  1193.  else
  1194.  
  1195.  printf("\nLa impresora tiene papel...");
  1196.  
  1197.  if (printer & 0x40) printf ("\nSI - Acuse de recibo...");
  1198.  
  1199.  else
  1200.  
  1201.  printf(\nNO - Acuse de recibo...");
  1202.  
  1203.  if (printer & 0x80) printf("\nImpresora no ocupada...");
  1204.  
  1205.  else
  1206.  
  1207.  printf("\nImpresora ocupada...");
  1208.  
  1209.  getch();
  1210.  
  1211.  exit(1);
  1212.  
  1213. }
  1214.  
  1215. Lluφs Company Ordo±o
  1216.  
  1217. Terrassa (Barcelona)
  1218.  
  1219.  
  1220. ELEGIR EL DIRECTORIO
  1221.  
  1222. Todos nos hemos sentido tentados en alguna ocasi≤n a escribir alg·n
  1223. peque±o programa que nos facilitase las tareas de movernos por nuestro
  1224. disco duro. Pero el principal inconveniente con el que topßbamos era
  1225. que un cambio en el ßrbol de directorios del mismo nos obligaba a
  1226. reescribir o recompilar la utilidad creada.
  1227.  
  1228. La siguiente rutina nos ofrece una interesante alternativa. En
  1229. efecto, el programa ½Eligdir╗ nos permite situarnos en cualquier
  1230. subdirectorio de la unidad por defecto, con tan s≤lo algunas
  1231. pulsaciones de teclas de funci≤n. Ocupa apenas 11 Kbytes y tan s≤lo
  1232. lee los 10 primeros subdirectorios de cada nivel (lo que puede ser
  1233. tanto una ventaja como un inconveniente).
  1234.  
  1235. Su algoritmo de funcionamiento es el siguiente. En primer lugar lee
  1236. las entradas en el directorio actual, almacenando en una cola los
  1237. directorios encontrados. A continuaci≤n se pide por teclado la
  1238. pulsaci≤n de una tecla de funci≤n y se salta al directorio asociado a
  1239. la misma leyendo la cola anterior. El proceso se repite hasta que la
  1240. entrada por teclado sea distinta de cualquiera de las teclas de
  1241. funci≤n.
  1242.  
  1243. A±adir por ·ltimo que este programa fue escrito para el compilador
  1244. Turbo C 2.0 de Borland, siendo recomendable su compilaci≤n en los
  1245. modelos tiny o small.
  1246.  
  1247. #include <dir.h>
  1248.  
  1249. #include <stdio.h>
  1250.  
  1251. #include <stdlib.h>
  1252.  
  1253. #include <dos.h>
  1254.  
  1255. #include <bios.h>
  1256.  
  1257. char todos[]="*.*";
  1258.  
  1259. /*patr≤n de b·squeda*/
  1260.  
  1261. struct ffblk f;
  1262.  
  1263. /*file control block*/
  1264.  
  1265. int atributos=FA_DIREC;
  1266.  
  1267. /*atributo de fichero=directorio*/
  1268.  
  1269. int ret;
  1270.  
  1271. /*resultado de funciones findfirst y findnext*/
  1272.  
  1273. char diract[MAXDIR];
  1274.  
  1275. /*cadena con el nombre del camino actual*/
  1276.  
  1277. extern unsigned _stacklen=512;
  1278.  
  1279. /*tama±o de pila y heap (mφnimo)*/
  1280.  
  1281. extern unsigned _heaplen=1024;
  1282.  
  1283. struct cola
  1284.  
  1285. /*cola de los directorios seleccionados*/
  1286.  
  1287. {char nombre[13];
  1288.  
  1289.  struct cola *sig;
  1290.  
  1291. } *pcab,*pcola;
  1292.  
  1293. /*punteros a cabeza y fin de la cola*/
  1294.  
  1295. void IniciaC()
  1296.  
  1297. /*Inicia la cola, borrßndola*/
  1298.  
  1299. { struct cola *p1,*p2;
  1300.  
  1301.  if (pcab!=NULL)
  1302.  
  1303.  {p1=pcab;p2=pcab->sig;
  1304.  
  1305.  while(p2!=NULL)
  1306.  
  1307.  {free(p1);
  1308.  
  1309.  p1=p2;
  1310.  
  1311.  p2=p2->sig;
  1312.  
  1313.  }
  1314.  
  1315.  free(p1);
  1316.  
  1317.  pcab=NULL;
  1318.  
  1319.  }
  1320.  
  1321. }
  1322.  
  1323. void MeterC(cad)
  1324.  
  1325. /*Mete un string en la cola*/
  1326.  
  1327. char cad[13];
  1328.  
  1329. {struct cola *p2;
  1330.  
  1331.  if ((p2=malloc(sizeof(*p2)))==NULL)
  1332.  
  1333.  {puts("No hay memoria suficiente");exit(0);}
  1334.  
  1335.  strcpy(p2->nombre,cad);
  1336.  
  1337.  p2->sig=NULL;
  1338.  
  1339.  if (pcab==NULL) pcab=p2;
  1340.  
  1341.  else pcola->sig=p2;
  1342.  
  1343.  pcola=p2;
  1344.  
  1345. }
  1346.  
  1347. EsvaciaC()
  1348.  
  1349. /*Comprueba si la cola estß vacφa*/
  1350.  
  1351. {return(pcab==NULL);}
  1352.  
  1353. void BuscaDIR()
  1354.  
  1355. /*Busca los directorios y los mete en la cola*/
  1356.  
  1357. {short c=0;
  1358.  
  1359.  IniciaC();
  1360.  
  1361.  ret=findfirst(todos,&f,atributos);
  1362.  
  1363.  /*busca el primero*/
  1364.  
  1365.  if (ret==-1) return;
  1366.  
  1367.  /*si no estß, salir*/
  1368.  
  1369.  if (f.ff_attrib==FA_DIREC && (f.ff_name[0]!='.'))
  1370.  
  1371.  /*si es directorio vßlido*/
  1372.  
  1373.  {MeterC(f.ff_name);c++;}
  1374.  
  1375.  /*meterlo en cola*/
  1376.  
  1377.  for(;;)
  1378.  
  1379.  {ret=findnext(&f);
  1380.  
  1381.  /*busca el siguiente*/
  1382.  
  1383.  if ((ret==-1) || (c>10)) break;
  1384.  
  1385.  /*si no encontrado o hay mßs de 10, salir*/
  1386.  
  1387.  if (f.ff_attrib==FA_DIREC) {MeterC(f.ff_name);c++;}
  1388.  
  1389.  }
  1390.  
  1391. if (EsvaciaC()) {puts("No encontrΘ directorios");exit(0);}
  1392.  
  1393. }
  1394.  
  1395. void Eligeopcion()
  1396.  
  1397. /*Muestra los directorios seleccionados y pide uno de ellos*/
  1398.  
  1399. {struct cola *p;
  1400.  
  1401.  int c,d;
  1402.  
  1403.  int tecla;
  1404.  
  1405.  getcurdir(0,diract);
  1406.  
  1407.  /*escribe directorio actual*/
  1408.  
  1409.  printf ("\n\n DIRECTORIO ACTUAL : \\%s",diract);
  1410.  
  1411.  puts ("\n Elige directorio: ");
  1412.  
  1413.  for(p=pcab,c=1;p!=NULL && c<=10;p=p->sig,c++)
  1414.  
  1415.  printf ("\n F%d - %s",c,p->nombre);
  1416.  
  1417.  puts ("\n OTRA CUALQUIERA - fin");
  1418.  
  1419.  tecla=bioskey(0)>>8;
  1420.  
  1421.  /*obtiene c≤digo tecla pulsada*/
  1422.  
  1423.  if ((tecla<0x3b)||(tecla>0x44)) exit(0);
  1424.  
  1425.  /*si no es tecla funci≤n, salir*/
  1426.  
  1427.  tecla-=0x3b;
  1428.  
  1429.  for(p=pcab,d=0;(tecla>d) && (p!=NULL);p=p->sig,d++);
  1430.  
  1431.  /*ir a dir seleccionado*/
  1432.  
  1433.  chdir(p->nombre);
  1434.  
  1435. }
  1436.  
  1437. main() /*Rutina principal*/
  1438.  
  1439. {BuscaDIR();
  1440.  
  1441.  while(!EsvaciaC())
  1442.  
  1443.  {Eligeopcion();
  1444.  
  1445.  BuscaDIR();
  1446.  
  1447.  }
  1448.  
  1449. }
  1450.  
  1451. Gonzalo Le≤n Manzano
  1452.  
  1453. Albacete
  1454.  
  1455.  
  1456. EFECTO DE SOMBREADO
  1457.  
  1458. Con esta funci≤n en C podemos dotar a nuestros programas de ventanas y
  1459. men·s con sombra. Las cajas son sencillas de hacer con las funciones
  1460. y procedimientos incluidos en C, pero la dificultad surge al crear las
  1461. sombras. Esta funci≤n nos ayudarß durante el proceso de sombreado.
  1462.  
  1463. El truco estß en leer los caracteres adecuados de la pantalla y
  1464. cambiarles el atributo que llevan asociado, es decir, el color de
  1465. primer plano y el de fondo. El nuevo atributo ha de ser gris sobre
  1466. negro.
  1467.  
  1468. La siguiente funci≤n se usa para crear el efecto descrito alrededor de
  1469. una regi≤n rectangular de coordenadas (x1,y1) (x2,y2).
  1470.  
  1471. // Esta funci≤n dibuja una "sombra" en funci≤n de las coordenadas
  1472. dadas
  1473.  
  1474. // Se supone que se habrß dibujado una caja con esas mismas
  1475. coordenadas
  1476.  
  1477. // Para hacer la sombra se cambia el atributo de los caracteres
  1478. adecuados
  1479.  
  1480. // a gris sobre negro
  1481.  
  1482. void Shadow(int x1,int y1,int x2,int y2)
  1483.  
  1484. {
  1485.  
  1486.  int j=0;
  1487.  
  1488.  char ch;
  1489.  
  1490.  union REGS r;
  1491.  
  1492.  // Se dibuja el lado inferior de la sombra
  1493.  
  1494.  for(j=x1+2;j<x2+3;j++)
  1495.  
  1496.  {
  1497.  
  1498.  gotoxy(j,y2+1); // coloco el cursor en la posici≤n adecuada
  1499.  
  1500.  r.h.ah=0x08;
  1501.  
  1502.  r.h.bh=0x00;
  1503.  
  1504.  int86(0x10,&r,&r); // consigo el carßcter de esa posici≤n
  1505.  
  1506.  ch=r.h.al; // ch contiene el carßcter
  1507.  
  1508.  textattr(7); // cambio el atributo del carßcter
  1509.  
  1510.  putch(ch); // y lo pongo de nuevo
  1511.  
  1512.  }
  1513.  
  1514.  //-- se dibuja el lado derecho de la sombra --
  1515.  
  1516.  for(j=y1+1;j<y2+1;j++)
  1517.  
  1518.  {
  1519.  
  1520.  gotoxy(x2+1,j); // coloco el cursor en la posici≤n adecuada
  1521.  
  1522.  r.h.ah=0x08;
  1523.  
  1524.  r.h.bh=0x00;
  1525.  
  1526.  int86(0x10,&r,&r); // consigo el carßcter de esa posici≤n
  1527.  
  1528.  ch=r.h.al; // ch contiene el carßcter
  1529.  
  1530.  textattr(7); // cambio el atributo del carßcter
  1531.  
  1532.  putch(ch); // y lo pongo de nuevo
  1533.  
  1534.  }
  1535.  
  1536.  for(j=y1+1;j<y2+1;j++)
  1537.  
  1538.  {
  1539.  
  1540.  gotoxy(x2+2,j); // coloco el cursor en posici≤n
  1541.  
  1542.  r.h.ah=0x08;
  1543.  
  1544.  r.h.bh=0x00;
  1545.  
  1546.  int86(0x10,&r,&r); // consigo el carßcter adecuado
  1547.  
  1548.  ch=r.h.al; // ch contiene el carßcter
  1549.  
  1550.  textattr(7); // cambio el atributo del carßcter
  1551.  
  1552.  putch(ch); // y lo vuelvo a colocar en su sitio
  1553.  
  1554.  }
  1555.  
  1556. }
  1557.  
  1558. Daniel Sßnchez Teodoro
  1559.  
  1560. Granada
  1561.  
  1562.  
  1563. DESARROLLA TUS PROPIOS ESTEREOGRAMAS
  1564.  
  1565. Con esta rutina podemos realizar estereogramas de una sola imagen.
  1566. Los estereogramas son esas extra±as imßgenes (tan de moda hoy en dφa)
  1567. que ½esconden╗ objetos en tres dimensiones, pero que pueden verse
  1568. empleando una determinada tΘcnica. Demetrio Fernßndez nos ha mandado
  1569. una rutina creada por Θl mismo que permite, a partir de una imagen,
  1570. desarrollar un estereograma. Estß escrita en C y sorprende por su
  1571. peque±o tama±o, pues tan s≤lo ocupa menos de 60 lφneas.
  1572.  
  1573. Para sacar provecho de todas sus prestaciones basta con crear el
  1574. dibujo o imagen, ponerla en pantalla y luego llamar al procedimiento
  1575. ½pantalla╗.
  1576.  
  1577. unsigned rep=40;
  1578.  
  1579. // ancho de repetici≤n
  1580.  
  1581. unsigned aleatorio[200];
  1582.  
  1583. // patr≤n con el que trabaja el programa
  1584.  
  1585. unsigned aleatorio2[200];
  1586.  
  1587. // patr≤n original
  1588.  
  1589. unsigned maximo=40;
  1590.  
  1591. //igual que rep pero este es temporal
  1592.  
  1593. unsigned NPUNTOS=1;
  1594.  
  1595. //el n·mero de puntos que se saltan
  1596.  
  1597. unsigned paralelo=1;
  1598.  
  1599. // modo de visualizaci≤n en paralelo o cruzado
  1600.  
  1601. // hace un simple negativo de la imagen
  1602.  
  1603. void genera(unsigned ini,unsigned fin)
  1604.  
  1605. // cuando hay que aumentar el aleatorio
  1606.  
  1607. // mete trozos del aleatorio2
  1608.  
  1609. {
  1610.  
  1611.  int i,j,d;
  1612.  
  1613.  d=fin-ini;
  1614.  
  1615.  j=random(rep-d);
  1616.  
  1617.  for(i=ini;i<fin;i++)
  1618.  
  1619.  {aleatorio[i]=aleatorio2[j+i-ini];}
  1620.  
  1621. }
  1622.  
  1623. void genera2(unsigned *tabl,unsigned ini,unsigned fin)
  1624.  
  1625. // aquφ genera puntos aleatorios pero
  1626.  
  1627. // podΘis poner lo que querßis como patron
  1628.  
  1629. {
  1630.  
  1631.  int i;
  1632.  
  1633.  for(i=ini;i<fin;i++)
  1634.  
  1635.  {tabl[i]=random(getmaxcolor());}
  1636.  
  1637. }
  1638.  
  1639. void adelante(unsigned ini,unsigned salto)
  1640.  
  1641. // incrementamos profundidad en la imagen
  1642.  
  1643.  
  1644. {
  1645.  
  1646.  unsigned i;
  1647.  
  1648.  for (i=maximo;i>ini;i--) aleatorio[i+NPUNTOS*salto]=aleatorio[i];
  1649.  
  1650.  maximo+=NPUNTOS*salto;
  1651.  
  1652.  genera(i,i+NPUNTOS*salto);
  1653.  
  1654. }
  1655.  
  1656. void atras(unsigned ini,unsigned salto)
  1657.  
  1658. // decrementamos profundidad en la imagen
  1659.  
  1660. {
  1661.  
  1662.  unsigned i;
  1663.  
  1664.  for (i=ini;i<maximo;i++) aleatorio[i]=aleatorio[i+NPUNTOS*salto];
  1665.  
  1666.  maximo-=NPUNTOS*salto;
  1667.  
  1668. }
  1669.  
  1670. void rastrealinea(unsigned numlin)
  1671.  
  1672. // genera cada lφnea
  1673.  
  1674. {
  1675.  
  1676.  unsigned i,j,k;
  1677.  
  1678.  unsigned color;
  1679.  
  1680.  color=0;
  1681.  
  1682.  maximo=rep;
  1683.  
  1684.  genera2(aleatorio,numlin,0,maximo*2);
  1685.  
  1686.  genera2(aleatorio2,numlin,0,maximo*2);
  1687.  
  1688.  j=0;
  1689.  
  1690.  for(i=0;i<getmaxx();i++)
  1691.  
  1692.  {if (paralelo) k=15-getpixel(i,numlin);
  1693.  
  1694.  else k=getpixel(i,numlin);
  1695.  
  1696.  if (k!=color)
  1697.  
  1698.  {if (k<color) adelante(j,color-k);
  1699.  
  1700.  else atras(j,k-color);
  1701.  
  1702.  color=k;}
  1703.  
  1704.  putpixel(i,numlin,aleatorio[j]);
  1705.  
  1706.  j=(j+1)%maximo;}
  1707.  
  1708. }
  1709.  
  1710. void pantalla(void)
  1711.  
  1712. // hace un estereograma de toda la pantalla
  1713.  
  1714. {
  1715.  
  1716. unsigned i;
  1717.  
  1718. for (i=0;i<=getmaxy();i++)
  1719.  
  1720. {
  1721.  
  1722.  if (i%2) rastrealinea(i);
  1723.  
  1724.  else rastrealinea(480-i);}
  1725.  
  1726. }
  1727.  
  1728. Nota sobre la visualizaci≤n: Christopher W. Tyler fue el creador de
  1729. los estereogramas de una sola imagen. Este tipo de estereogramas no
  1730. son en verdad una sola imagen, sino siete u ocho imßgenes iguales
  1731. puestas unas juntas con las otras hasta formar una ·nica imagen y el
  1732. efecto de profundidad. La tΘcnica de visualizaci≤n consiste en poner
  1733. el punto focal detras de la pßgina que estamos viendo, tratando de
  1734. situar la vista mßs allß de la hoja. Se consigue acercando la imagen
  1735. (en este caso la pantalla) a los ojos y despuΘs separßndola (en este
  1736. caso la cabeza) hasta que veamos las tres dimensiones.
  1737.  
  1738. Demetrio Fernßndez Alvarez
  1739.  
  1740. Oviedo
  1741.  
  1742.  
  1743. TRATAMIENTO DE IMAGENES
  1744.  
  1745. Las siguientes rutinas son dos procedimientos que nos van a permitir,
  1746. en primer lugar, capturar cualquier imagen que se pueda sacar por
  1747. pantalla (incluso aquellas de 256 colores), para convertirla en un
  1748. formato reconocible por la segunda rutina, que serß la que dibujarß
  1749. esa misma imagen pero adaptßndola a un polφgono que le pasaremos como
  1750. parßmetro.
  1751.  
  1752. Para utilizar estas rutinas en los nuevos programas hay que incluir el
  1753. fichero ½trans_ima.h╗, ademßs de indicar a nuestro compilador que debe
  1754. enlazar nuestro programa y el fichero ½trans_ima.c╗.
  1755.  
  1756. El programa ½Trans_ima.h╗ es el siguiente:
  1757.  
  1758. /* TRANSFORMA IMAGEN
  1759.  
  1760. Este conjunto de rutinas estß pensado para capturar imßgenes y luego
  1761. adaptarlas a cualquier polφgono, sea o no rectangular.
  1762.  
  1763. - captura: Coge una zona de la pantalla grßfica y la captura en el
  1764. formato t_imagen.
  1765.  
  1766. - D_dibuja: Adapta la imagen que se le pasa como parßmetro al
  1767. polφgono que le indicamos en la variable de tipo t_puntos.
  1768.  
  1769. El tipo t_puntos no es mßs que un registro con cuatro puntos que
  1770. se±alan los vΘrtices de un polφgono.
  1771.  
  1772. */
  1773.  
  1774.  struct t_imagen
  1775.  
  1776.  {unsigned tam_max_x,tam_max_y;
  1777.  
  1778.  unsigned char huge *ptr;
  1779.  
  1780.  };
  1781.  
  1782.  struct t_punto
  1783.  
  1784.  {int x,y;};
  1785.  
  1786.  struct t_puntos
  1787.  
  1788.  {struct t_punto p1,p2,p3,p4;};
  1789.  
  1790.  void D_dibuja (struct t_imagen,struct t_puntos);
  1791.  
  1792.  struct t_imagen captura (int,int,int,int);
  1793.  
  1794.  
  1795. El programa ½Trans_ima.c╗ es el siguiente:
  1796.  
  1797.  #include "alloc.h"
  1798.  
  1799.  #include "graphics.h"
  1800.  
  1801.  #include "math.h"
  1802.  
  1803.  #include "trans_ima.h"
  1804.  
  1805.  struct t_coef
  1806.  
  1807.  {float x,y;};
  1808.  
  1809.  struct t_coefs
  1810.  
  1811.  {struct t_coef c1,c2,c3,c4;};
  1812.  
  1813.  void calcula_coef (struct t_puntos,struct t_coefs *);
  1814.  
  1815.  void calcula_incremento_a (struct t_puntos,float *);
  1816.  
  1817.  void calcula_incremento_b (struct t_puntos puntos,float *incb);
  1818.  
  1819.  struct t_punto S_destino (float,float,struct t_coefs);
  1820.  
  1821.  struct t_punto S_origen (struct t_imagen,float,float);
  1822.  
  1823.  int color_origen (struct t_imagen,struct t_punto);
  1824.  
  1825.  struct t_imagen captura (int x1,int y1,int x2,int y2)
  1826.  
  1827.  {unsigned i,j;
  1828.  
  1829.  struct t_imagen imagen;
  1830.  
  1831.  unsigned seg;
  1832.  
  1833.  int error;
  1834.  
  1835.  imagen.ptr = farmalloc ((unsigned long) (y2-y1+1)*(x2-x1+1));
  1836.  
  1837.  if (imagen.ptr != NULL)
  1838.  
  1839.  {imagen.tam_max_x = x2-x1;
  1840.  
  1841.  imagen.tam_max_y = y2-y1;
  1842.  
  1843.  for (i=0;i<=y2-y1;i++)
  1844.  
  1845.  {for (j=0;j<=x2-x1;j++)
  1846.  
  1847.  {imagen.ptr [(unsigned long) i*(x2-x1+1)+j] = getpixel (x1+j,y1+i);}
  1848.  
  1849.  }
  1850.  
  1851.  }
  1852.  
  1853.  return (imagen);
  1854.  
  1855.  }
  1856.  
  1857.  void calcula_coef (struct t_puntos puntos,struct t_coefs *coef)
  1858.  
  1859.  {
  1860.  
  1861.  coef->c1.x = puntos.p1.x-puntos.p2.x+puntos.p3.x-puntos.p4.x;
  1862.  
  1863.  coef->c1.y = puntos.p1.y-puntos.p2.y+puntos.p3.y-puntos.p4.y;
  1864.  
  1865.  coef->c2.x = puntos.p4.x-puntos.p3.x;
  1866.  
  1867.  coef->c2.y = puntos.p4.y-puntos.p3.y;
  1868.  
  1869.  coef->c3.x = puntos.p2.x-puntos.p3.x;
  1870.  
  1871.  coef->c3.y = puntos.p2.y-puntos.p3.y;
  1872.  
  1873.  coef->c4.x = puntos.p3.x;
  1874.  
  1875.  coef->c4.y = puntos.p3.y;
  1876.  
  1877.  }
  1878.  
  1879.  struct t_punto S_destino (float alfa,float beta,struct t_coefs coef)
  1880.  
  1881.  {struct t_punto p;
  1882.  
  1883.  p.x = (int) (alfa*beta*coef.c1.x + alfa*coef.c2.x + beta*coef.c3.x +
  1884.  coef.c4.x);
  1885.  
  1886.  p.y = (int) (alfa*beta*coef.c1.y + alfa*coef.c2.y + beta*coef.c3.y +
  1887.  coef.c4.y);
  1888.  
  1889.  return (p);
  1890.  
  1891.  }
  1892.  
  1893.  struct t_punto S_origen (struct t_imagen imagen,float alfa,float beta)
  1894.  
  1895.  {struct t_punto p;
  1896.  
  1897.  p.x = imagen.tam_max_x -(int) (beta*imagen.tam_max_x);
  1898.  
  1899.  p.y = imagen.tam_max_y -(int) (alfa*imagen.tam_max_y);
  1900.  
  1901.  return (p);
  1902.  
  1903.  }
  1904.  
  1905.  int color_origen (struct t_imagen imagen,
  1906.  
  1907.  struct t_punto p)
  1908.  
  1909.  {
  1910.  
  1911.  return (imagen.ptr [(unsigned long) p.y*(imagen.tam_max_x+1)+p.x]);
  1912.  
  1913.  }
  1914.  
  1915.  void calcula_incremento_a (struct t_puntos puntos,float *inca)
  1916.  
  1917.  {unsigned dist1,dist2;
  1918.  
  1919.  float dist;
  1920.  
  1921.  int vx,vy;
  1922.  
  1923.  vx = abs (puntos.p2.x-puntos.p1.x);
  1924.  
  1925.  vy = abs (puntos.p2.y-puntos.p1.y);
  1926.  
  1927.  dist1 = ((vx > vy) ? vx : vy);
  1928.  
  1929.  vx = abs (puntos.p3.x-puntos.p4.x);
  1930.  
  1931.  vy = abs (puntos.p3.y-puntos.p4.y);
  1932.  
  1933.  dist2 = ((vx > vy) ? vx : vy);
  1934.  
  1935.  dist = (((dist1) > (dist2)) ? (dist1) : (dist2));
  1936.  
  1937.  *inca = 1/(dist+1);
  1938.  
  1939.  }
  1940.  
  1941.  void calcula_incremento_b (struct t_puntos puntos,float *incb)
  1942.  
  1943.  {unsigned dist1,dist2;
  1944.  
  1945.  float dist;
  1946.  
  1947.  int vx,vy;
  1948.  
  1949.  vx = abs (puntos.p4.x-puntos.p1.x);
  1950.  
  1951.  vy = abs (puntos.p4.y-puntos.p1.y);
  1952.  
  1953.  dist1 = ((vx > vy) ? vx : vy);
  1954.  
  1955.  vx = abs (puntos.p2.x-puntos.p3.x);
  1956.  
  1957.  vy = abs (puntos.p2.y-puntos.p3.y);
  1958.  
  1959.  dist2 = ((vx > vy) ? vx : vy);
  1960.  
  1961.  dist = (((dist1) > (dist2)) ? (dist1) : (dist2));
  1962.  
  1963.  *incb = 1/(dist+1);
  1964.  
  1965.  }
  1966.  
  1967.  void D_dibuja (struct t_imagen origen,
  1968.  
  1969.  struct t_puntos puntos)
  1970.  
  1971.  {float alfa,beta;
  1972.  
  1973.  struct t_punto p;
  1974.  
  1975.  struct t_coefs coef;
  1976.  
  1977.  int color;
  1978.  
  1979.  float inca,incb;
  1980.  
  1981.  calcula_incremento_a (puntos,&inca);
  1982.  
  1983.  calcula_incremento_b (puntos,&incb);
  1984.  
  1985.  calcula_coef (puntos,&coef);
  1986.  
  1987.  for (alfa=0;alfa<=1;alfa+=inca)
  1988.  
  1989.  for (beta=0;beta<=1;beta+=incb)
  1990.  
  1991.  {p = S_origen (origen,alfa,beta);
  1992.  
  1993.  color = color_origen (origen,p);
  1994.  
  1995.  p = S_destino (alfa,beta,coef);
  1996.  
  1997.  putpixel (p.x,p.y,color);
  1998.  
  1999.  }
  2000.  
  2001.  }
  2002.  
  2003. Siguiendo estos pasos, tenemos a nuestra disposici≤n dos rutinas:
  2004.  
  2005. - struct t_imagen captura(int x1, int y1, int x2, int y2)
  2006.  
  2007. - void D_dibuja (struct t_imagen imagen, struct t_puntos p)
  2008.  
  2009. La primera funci≤n captura el mapa de bits comprendido entre los
  2010. puntos (x1,y1) y (x2,y2), devolviendo un registro de tipo t_imagen, en
  2011. el que queda almacenada.
  2012.  
  2013. El segundo procedimiento coge la imagen previamente capturada y la
  2014. dibuja adaptßndola al polφgono de cuatro vΘrtices indicado por la
  2015. variable p.
  2016.  
  2017. Hemos de tener en cuenta que la imagen capturada se almacena en
  2018. memoria principal como una matriz de char, con un byte por cada
  2019. pixel que capturemos. Por lo que si los bitmaps van a ser muy
  2020. grandes tendremos que compilar el programa en modelos como ½Compact╗.
  2021.  
  2022. En el siguiente programa vemos un ejemplo de la utilizaci≤n de estas
  2023. rutinas:
  2024.  
  2025.  #include "alloc.h"
  2026.  
  2027.  #include "graphics.h"
  2028.  
  2029.  #include "stdio.h"
  2030.  
  2031.  #include "fcntl.h"
  2032.  
  2033.  #include "io.h"
  2034.  
  2035.  #include "trans_ima.h"
  2036.  
  2037.  struct t_imagen carga_origen (char *);
  2038.  
  2039.  int inicia_graficos ();
  2040.  
  2041.  int main ()
  2042.  
  2043.  {struct t_puntos puntos;
  2044.  
  2045.  struct t_imagen origen;
  2046.  
  2047.  char *cadena = "PC-ACTUAL";
  2048.  
  2049.  char *aux = " \0";
  2050.  
  2051.  int i;
  2052.  
  2053.  inicia_graficos ();
  2054.  
  2055.  /* PRIMERO SIMPLEMENTE DIBUJAMOS UNA IMAGEN EN LA PANTALLA */
  2056.  
  2057.  settextstyle (DEFAULT_FONT,HORIZ_DIR,3);
  2058.  
  2059.  moveto (0,0);
  2060.  
  2061.  for (i=0;i < strlen (cadena);i++)
  2062.  
  2063.  {setcolor (i+1);
  2064.  
  2065.  strnset (aux,cadena [i],1);
  2066.  
  2067.  outtext (aux);
  2068.  
  2069.  }
  2070.  
  2071.  setcolor (i+1);
  2072.  
  2073.  line (0,textheight (cadena),textwidth (cadena),textheight (cadena));
  2074.  
  2075.  /* CAPTURAMOS LA PARTE DE LA PANTALLA QUE NOS INTERESA EN UNA VARIABLE
  2076.  DE TIPO ORIGEN */
  2077.  
  2078.  origen.tam_max_x = textwidth (cadena);
  2079.  
  2080.  origen.tam_max_y = textheight (cadena);
  2081.  
  2082.  origen = captura (0,0,origen.tam_max_x,origen.tam_max_y);
  2083.  
  2084.  settextstyle (DEFAULT_FONT,HORIZ_DIR,1);
  2085.  
  2086.  setcolor (WHITE);
  2087.  
  2088.  outtextxy (0,getmaxy ()-textheight ("P"),
  2089.  
  2090.  "Pulsa una tecla para ver la imagen transformada...");
  2091.  
  2092.  getch ();
  2093.  
  2094.  if (origen.ptr != NULL) /* ┐HA HABIDO ERROR EN ASIGNACION DE MEMORIA? */
  2095.  
  2096.  {cleardevice ();
  2097.  
  2098.  /* DIBUJAMOS LA IMAGEN TRANSFORMADA */
  2099.  
  2100.  puntos.p1.x = 0;puntos.p1.y = 0;
  2101.  
  2102.  puntos.p2.x = 0;puntos.p2.y = getmaxy ();
  2103.  
  2104.  puntos.p3.x = getmaxx ()/2-50;puntos.p3.y = getmaxy ()/2+40;
  2105.  
  2106.  puntos.p4.x = getmaxx ()/2-50;puntos.p4.y = getmaxy ()/2-40;
  2107.  
  2108.  D_dibuja (origen,puntos);
  2109.  
  2110.  puntos.p1.x = getmaxx ()/2-40;puntos.p1.y = getmaxy ()/2+50;
  2111.  
  2112.  puntos.p2.x = 0;puntos.p2.y = getmaxy ();
  2113.  
  2114.  puntos.p3.x = getmaxx ();puntos.p3.y = getmaxy ();
  2115.  
  2116.  puntos.p4.x = getmaxx () /2+40;puntos.p4.y = getmaxy ()/2+50;
  2117.  
  2118.  D_dibuja (origen,puntos);
  2119.  
  2120.  puntos.p3.x = getmaxx ()/2+50;puntos.p3.y = getmaxy ()/2+40;
  2121.  
  2122.  puntos.p2.x = getmaxx ();puntos.p2.y = getmaxy ();
  2123.  
  2124.  puntos.p1.x = getmaxx ();puntos.p1.y = 0;
  2125.  
  2126.  puntos.p4.x = getmaxx ()/2+50;puntos.p4.y = getmaxy ()/2-40;
  2127.  
  2128.  D_dibuja (origen,puntos);
  2129.  
  2130.  puntos.p2.x = 0;puntos.p2.y = 0;
  2131.  
  2132.  puntos.p1.x = getmaxx ()/2-40;puntos.p1.y = getmaxy ()/2-50;
  2133.  
  2134.  puntos.p4.x = getmaxx ()/2+40;puntos.p4.y = getmaxy ()/2-50;
  2135.  
  2136.  puntos.p3.x = getmaxx ();puntos.p3.y = 0;
  2137.  
  2138.  D_dibuja (origen,puntos);
  2139.  
  2140.  free ((void *) origen.ptr);
  2141.  
  2142.  getch ();
  2143.  
  2144.  }
  2145.  
  2146.  else {closegraph ();
  2147.  
  2148.  printf ("\nError en asignacion de memoria\n");
  2149.  
  2150.  exit (1);
  2151.  
  2152.  }
  2153.  
  2154.  closegraph ();
  2155.  
  2156.  return (0);
  2157.  
  2158.  }
  2159.  
  2160.  int inicia_graficos ()
  2161.  
  2162.  {int driver,modo,errorcode;
  2163.  
  2164.  driver = DETECT;
  2165.  
  2166.  initgraph (&driver,&modo,"");
  2167.  
  2168.  errorcode = graphresult();
  2169.  
  2170.  if (errorcode != grOk)
  2171.  
  2172.  {
  2173.  
  2174.  printf("Error en graficos: %s\n", grapherrormsg(errorcode));
  2175.  
  2176.  printf("Pulsa una tecla para terminar.");
  2177.  
  2178.  getch();
  2179.  
  2180.  exit(1);
  2181.  
  2182.  }
  2183.  
  2184.  return (graphresult ());
  2185.  
  2186.  }
  2187.  
  2188.  
  2189. Marcial Martφnez L≤pez
  2190.  
  2191. Valencia
  2192.  
  2193.  
  2194.  
  2195.  
  2196.  
  2197.  
  2198.